package com.mcxx.util;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.google.gson.Gson;
import com.mcxx.common.exception.HttpStatusException;
import com.mcxx.result.BaseResult;
import com.yinhai.ta404.core.exception.AppException;
import okhttp3.*;
import org.apache.commons.lang3.StringUtils;

import java.io.*;
import java.net.SocketTimeoutException;
import java.net.URL;
import java.net.URLConnection;
import java.util.*;
import java.util.concurrent.TimeUnit;



public class OkHttpUtil {
    private static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(OkHttpUtil.class);

    private static OkHttpClient client;

    private static final String DEFAULT_MEDIA_TYPE = "application/json; charset=utf-8";

    private static final int CONNECT_TIMEOUT = 5000;

    private static final int READ_TIMEOUT = 7000;

    private static final String GET = "GET";

    private static final String POST = "POST";

    public static String TOKEN = "";
    public static String ABUTMENT_TOKEN = "";

    public static Date beginDate = null;


    private static OkHttpClient getInstance() {
        if (client == null) {
            synchronized (OkHttpClient.class) {
                if (client == null) {
                    client = new OkHttpClient.Builder()
                            .connectTimeout(CONNECT_TIMEOUT, TimeUnit.SECONDS)
                            .readTimeout(READ_TIMEOUT, TimeUnit.SECONDS)
                            .addInterceptor(new OkHttpInterceptor())
                            .build();
                }
            }
        }
        return client;
    }


    public static String doGet(String url) throws HttpStatusException {
        try {
            long startTime = System.currentTimeMillis();
            addRequestLog(GET, url, null, null);

            Request request = new Request.Builder().url(url).build();

            Response response = getInstance().newCall(request).execute();
            int httpCode = response.code();
            String result;
            if (response.body() != null) {
                result = response.body().string();
                addResponseLog(httpCode, result, startTime);
            } else {
                throw new RuntimeException("exception in OkHttpUtil,response body is null");
            }
            return handleHttpResponse(httpCode, result, response);
        } catch (Exception ex) {
            handleHttpThrowable(ex, url);
            return StringUtils.EMPTY;
        }
    }



    public static String doPost(String url, String postBody, String mediaType) {
        String result = null;
        try {
            long startTime = System.currentTimeMillis();
            addRequestLog(POST, url, postBody, null);

            MediaType createMediaType = MediaType.parse(mediaType == null ? DEFAULT_MEDIA_TYPE : mediaType);
            Request.Builder builder = new Request.Builder();
            builder.addHeader("Content-Type", "application/json").url(url)
                    .post(RequestBody.create(createMediaType, postBody));
            Request request = builder.build();
            Response response = getInstance().newCall(request).execute();
            int httpCode = response.code();
            if (response.body() != null) {
                result = response.body().string();
                addResponseLog(httpCode, result, startTime);
                if ("".equals(result)) {
                    errorLog(POST, url, postBody, null, "response result is null");
                }
            } else {
                errorLog(POST, url, postBody, null, "response body is null");
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return result;
    }


    public static String doPost(String url, Map<String, String> parameterMap, String mediaType) {
        String result = "";
        try {
            long startTime = System.currentTimeMillis();
            List<String> parameterList = new ArrayList<>();
            FormBody.Builder builder = new FormBody.Builder();
            if (parameterMap.size() > 0) {
                parameterMap.keySet().forEach(parameterName -> {
                    String value = parameterMap.get(parameterName);
                    builder.add(parameterName, value);
                    parameterList.add(parameterName + ":" + value);
                });
            }

            addRequestLog(POST, url, null, Arrays.toString(parameterList.toArray()));
            MediaType createMediaType = MediaType.parse(mediaType == null ? DEFAULT_MEDIA_TYPE : mediaType);
            Request request = new Request.Builder()
                    .addHeader("Content-Type", "application/json; charset=UTF-8")
                    .addHeader("token", TOKEN)
                    .url(url)
                    .post(RequestBody.create(createMediaType, JSON.toJSONString(parameterMap)))
                    .build();

            Response response = getInstance().newCall(request).execute();
            int httpCode = response.code();
            if (response.body() != null) {
                result = response.body().string();
                addResponseLog(httpCode, result, startTime);
                if ("".equals(result)) {
                    errorLog(POST, url, null, Arrays.toString(parameterList.toArray()), "response result is null");
                }
            } else {
                errorLog(POST, url, null, Arrays.toString(parameterList.toArray()), "response body is null");
            }
            return handleHttpResponse(httpCode, result, response);

        } catch (Exception ex) {
            logger.error("POST失败", ex);
            result = ex.getMessage();
        }
        finally {
            return result;
        }
    }

    public static String doPost(String url, Map<String, String> param) {
        return OkHttpUtil.doPost(url, param, null);
    }


    public static String doPost(String url, String paramStr) {
        String result = "";
        try {
            long startTime = System.currentTimeMillis();
            MediaType createMediaType = MediaType.parse(DEFAULT_MEDIA_TYPE);
            Request request = new Request.Builder()
                    .addHeader("Content-Type", "application/json; charset=UTF-8")
                    .addHeader("token", TOKEN)
                    .url(url)
                    .post(RequestBody.create(createMediaType, paramStr))
                    .build();

            Response response = getInstance().newCall(request).execute();
            int httpCode = response.code();
            if (response.body() != null) {
                result = response.body().string();
                addResponseLog(httpCode, result, startTime);
            } else {
                errorLog(POST, url, null, paramStr, "response body is null");
            }
            return handleHttpResponse(httpCode, result, response);

        } catch (Exception ex) {
            logger.error("POST失败", ex);
            result = ex.getMessage();
        }
        finally {
            return result;
        }
    }


    public static String doPostWithHeader(String url, Map<String, String> parameterMap,Map<String,String> header, String mediaType) {
        String result = "";
        try {
            long startTime = System.currentTimeMillis();
            List<String> parameterList = new ArrayList<>();
            Gson gson = new Gson();
            addRequestLog(POST, url, null,    gson.toJson(parameterMap));
            MediaType createMediaType = MediaType.parse(mediaType == null ? DEFAULT_MEDIA_TYPE : mediaType);
            Request.Builder rBuilder = new Request.Builder();
            if(header!=null){
                Set<String> set = header.keySet();
                for(String key:set){
                    rBuilder.addHeader(key,header.get(key));
                }
            }
            Request request = rBuilder
                    .addHeader("Content-Type", "application/json")
                    .addHeader("token", TOKEN)
                    .url(url)
                    .post(RequestBody.create(createMediaType, JSON.toJSONString(parameterMap)))
                    .build();
            Response response = getInstance().newCall(request).execute();
            int httpCode = response.code();
            if (response.body() != null) {
                result = response.body().string();
                addResponseLog(httpCode, result, startTime);
                if ("".equals(result)) {
                    errorLog(POST, url, null, Arrays.toString(parameterList.toArray()), "response result is null");
                }
            } else {
                errorLog(POST, url, null, Arrays.toString(parameterList.toArray()), "response body is null");
            }
            return handleHttpResponse(httpCode, result, response);

        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return result;
    }


    public static String doPostWithFile(String url,Map<String,String> header, Map<String,String> parameterMap, File file){
        String result = "";
        try {
            long startTime = System.currentTimeMillis();
            List<String> parameterList = new ArrayList<>();
            MultipartBody.Builder builder = new MultipartBody.Builder();
            if (parameterMap!=null && parameterMap.size() > 0) {
                parameterMap.keySet().forEach(parameterName -> {
                    builder.addFormDataPart(parameterName,parameterMap.get(parameterName));
                });
            }
            if(file !=null){
                builder.addFormDataPart("imgFile",file.getName(),RequestBody.create(MediaType.parse("application/octet-stream"),file));
            }
            Gson gson = new Gson();
            addRequestLog(POST, url, null, gson.toJson(parameterMap));
            RequestBody body = builder.build();
            Request.Builder rbuilder =  new  Request.Builder().post(body).url(url).addHeader("Content-Type","multipart/form-data");
            if(header !=null){
                for(String key:header.keySet()){
                    logger.info(key);
                    logger.info(header.get(key));
                    rbuilder.addHeader(key,header.get(key));
                }
            }
            Request request = rbuilder.build();
            Response response = getInstance().newCall(request).execute();
            int httpCode = response.code();
            if (response.body() != null) {
                result = response.body().string();
                addResponseLog(httpCode, result, startTime);
                if ("".equals(result)) {
                    errorLog(POST, url, null, Arrays.toString(parameterList.toArray()), "response result is null");
                }
            } else {
                errorLog(POST, url, null, Arrays.toString(parameterList.toArray()), "response body is null");
            }
            return handleHttpResponse(httpCode, result, response);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return result;
    }


    public static String doPostWithHeader(String url, String jsonStr,Map<String,String> header) {
        String result = "";
        try {
            long startTime = System.currentTimeMillis();
            List<String> parameterList = new ArrayList<>();
            addRequestLog(POST, url, null,   jsonStr);
            MediaType createMediaType = MediaType.parse(DEFAULT_MEDIA_TYPE);
            Request.Builder rBuilder = new Request.Builder();
            if(header!=null){
                Set<String> set = header.keySet();
                for(String key:set){
                    rBuilder.addHeader(key,header.get(key));
                }
            }
            Request request = rBuilder
                    .addHeader("Content-Type", "application/json")
                    .addHeader("token", TOKEN)
                    .url(url)
                    .post(RequestBody.create(createMediaType,jsonStr))
                    .build();
            Response response = getInstance().newCall(request).execute();
            int httpCode = response.code();
            if (response.body() != null) {
                result = response.body().string();
                addResponseLog(httpCode, result, startTime);
                if ("".equals(result)) {
                    errorLog(POST, url, null, Arrays.toString(parameterList.toArray()), "response result is null");
                }
            } else {
                errorLog(POST, url, null, Arrays.toString(parameterList.toArray()), "response body is null");
            }
            return handleHttpResponse(httpCode, result, response);

        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return result;
    }



    public static String doPost(String url, String postBody, String mediaType, String callMethod, String crc) {
        logger.info("post url:{}", url);
        String result = null;
        try {
            long startTime = System.currentTimeMillis();
            MediaType createMediaType = MediaType.parse(mediaType == null ? DEFAULT_MEDIA_TYPE : mediaType);
            Request.Builder builder = new Request.Builder();
            if ("login".equals(callMethod)) {
                builder.addHeader("CRC", crc)
                        .url(url)
                        .post(RequestBody.create(createMediaType, postBody));
            }
            else {
                logger.info("TOKEN:{}/{}", ABUTMENT_TOKEN, builder);
                builder.addHeader("Content-Type", "application/json")
                        .addHeader("token", ABUTMENT_TOKEN)
                        .addHeader("CRC", crc)
                        .url(url)
                        .post(RequestBody.create(createMediaType, postBody));
            }
            Request request = builder.build();
            Response response = getInstance().newCall(request).execute();
            int httpCode = response.code();
            ResponseBody responseBody = response.body();
            if (responseBody != null) {
                result = responseBody.string();
                addResponseLog(httpCode, result, startTime);
                if ("login".equals(callMethod)) {
                    Result<String> loginResult = JsonUtil.jsonToPojo(result, Result.class);
                    if (loginResult.getCode() == 1) {
                        ABUTMENT_TOKEN = loginResult.getData();
                    }
                }
            }
        } catch (Exception ex) {
            logger.error(ex.getMessage(), ex);
        }
        return result;
    }

    private static String getHeaderFileName(Response response) {
        String dispositionHeader = response.header("Content-Disposition");
        if (!StringUtils.isEmpty(dispositionHeader)) {
            dispositionHeader.replace("attachment;filename=", "");
            dispositionHeader.replace("filename*=utf-8", "");
            String[] strings = dispositionHeader.split("; ");
            if (strings.length > 1) {
                dispositionHeader = strings[1].replace("filename=", "");
                dispositionHeader = dispositionHeader.replace("\"", "");
                return dispositionHeader;
            }
            return "";
        }
        return "";
    }

    private static void errorLog(String method, String url, String body, String formParam, String error) {
        logger.info("===========================error begin================================================");
        logger.info("URI          : {}", url);
        logger.info("Method       : {}", method);
        logger.info("error          : {}", error);
        if (StringUtils.isNotBlank(body)) {
            logger.info("Request body : {}", body);
        }
        if (StringUtils.isNotBlank(formParam)) {
            logger.info("Request param: {}", formParam);
        }
        logger.info("---------------------------error end--------------------------------------------------");
    }

    private static void addRequestLog(String method, String url, String body, String formParam) {
        logger.info("===========================request begin================================================");
        logger.info("URI          : {}", url);
        logger.info("Method       : {}", method);
        if (StringUtils.isNotBlank(body)) {
            logger.info("Request body : {}", body);
        }
        if (StringUtils.isNotBlank(formParam)) {
            logger.info("Request param: {}", formParam);
        }
        logger.info("TOKEN          : {}", TOKEN);
        logger.info("---------------------------request end--------------------------------------------------");
    }

    private static void addResponseLog(int httpCode, String result, long startTime) {
        logger.info("===========================response begin================================================");
        long endTime = System.currentTimeMillis();
        logger.info("Status       : {}", httpCode);
        logger.info("Response     : {}", result);
        logger.info("Time         : {} ms", endTime - startTime);
        logger.info("===========================response end================================================");
    }

    private static String handleHttpResponse(int httpCode, String result, Response response) throws HttpStatusException {
        if (response.isSuccessful()) {
            return result;
        }
        return null;
    }

    private static void handleHttpThrowable(Exception ex, String url) throws HttpStatusException {
        if (ex instanceof HttpStatusException) {
            throw (HttpStatusException) ex;
        }
        logger.error("OkHttp error url: " + url, ex);
        if (ex instanceof SocketTimeoutException) {
            throw new RuntimeException("request time out of OkHttp when do get:" + url);
        }
        throw new RuntimeException(ex);
    }
    public static void main(String[] args) {
        String url = "http://mc.bab.ac.cn:8089/mint/jz/order/subsistenceApi";
        String body="{\n" +
                "  \"AXAA2701\": \"430103004006\",\n" +
                "  \"AXAA9952\": \"2021-09-13 09:39:29.0\",\n" +
                "  \"AXCP0035\": \"01\",\n" +
                "  \"AXDF0004\": \"340103198506020017\",\n" +
                "  \"BBAP9209\": \"测试推送\",\n" +
                "  \"BBAX9940\": \"01\",\n" +
                "}";
        Map map = JSON.parseObject(body, Map.class);
        String s = JSONObject.toJSONString(map);
        String ddd = JSON.toJSONString(JSON.parse(s));
        System.out.println("s:"+s);
        System.out.println("ddd:"+ddd);
        OkHttpUtil.doPost(url,ddd,null);

    }
}
